/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package percussiongenerator.gui;

import percussiongenerator.input.InputStartOnly;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.constants.ModelConstants;
import org.jfonia.constants.SymbolConstants;
import org.jfonia.model.PerformanceNode;
import org.jfonia.model.PerformanceSequence;
import org.jfonia.model.Sequence;
import org.jfonia.model.Staff;
import org.jfonia.model.TempoMap;
import org.jfonia.model.TempoNode;
import org.jfonia.model.elements.TimeSignature;
import org.jfonia.model.quantize.BPMQuantizer;
import percussiongenerator.gui.view.View;
import percussiongenerator.model.Track;
import percussiongenerator.model.TrackCollection;

/**
 *
 * @author Jannes Plyson
 */
public class TappingPanel extends JPanel implements FocusListener,KeyListener{
    private InputStartOnly input;
    private Color c1;
    private Color c2;
    private boolean pressed;
    private TrackCollection trackCollection;
    private JLabel label;
    private MutableValueNode<View> selectedView;
    private Long playingTime;

    public TappingPanel(TrackCollection trackCollection, MutableValueNode selectedView){
        this.setPreferredSize(new Dimension(100,100));
        this.setMinimumSize(new Dimension(100,100));        
        this.trackCollection = trackCollection;
        this.selectedView = selectedView;
        this.setFocusable(true);
        this.setFocusTraversalKeysEnabled(false);
        this.addFocusListener(this);
        this.addKeyListener(this);
        this.setOpaque(true);
        this.setBackground(Color.white);
        this.setBorder(BorderFactory.createTitledBorder("Keyboard"));
        this.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                requestFocus();
            }
        });
        c1 = Color.WHITE;
        c2 = Color.BLACK;        
        this.setBackground(c1);        
        pressed = false;
        this.setLayout(new BorderLayout());
        label = new JLabel();
        label.setText("<html>Click here to start tapping using the keyboard");
        this.add(label,BorderLayout.CENTER);        
    }

    public void start(){
        input = new InputStartOnly();        
        label.setText("<html>Start tapping by pressing space or a letter. To end input press enter</html>");
        playingTime = null;
    }

    public void focusGained(FocusEvent e) {
        start();
    }

    public void focusLost(FocusEvent e) {        
        label.setText("<html>Click here to start tapping using the keyboard");
    }

    public void keyTyped(KeyEvent e){        
    }

    public void keyPressed(KeyEvent e) {
        if(!e.isActionKey() && e.getKeyCode() != KeyEvent.VK_ENTER){
            if(!pressed){
                pressed = true;
                input.addInput(System.nanoTime());
                long playerTime = trackCollection.getPlayerTime();
                if(playingTime == null && trackCollection.isPlaying()){
                    playingTime = playerTime-trackCollection.getSoundDelay();
                }
                if(this.getBackground() == c1){
                    this.setBackground(c2);
                    label.setForeground(c1);
                }else{
                    this.setBackground(c1);
                    label.setForeground(c2);
                }
            }            
        }else if(e.getKeyCode() == KeyEvent.VK_ENTER){            
            Staff staff = input.getStaff();
            if(trackCollection.isPlaying() && selectedView.getValue() != null){
                Staff staffSelected = selectedView.getValue().getTrack().getStaff();
                staffSelected.getToneSequence().setLockNotation(true);
                staffSelected.getToneSequence().setLockPerformance(true);
                TempoNode tn = ((TempoNode)staffSelected.getTempoMap().getIntervalFromIndex(0)).clone();
                TimeSignature ts = ((TimeSignature)staffSelected.getSequence(TimeSignature.class).getIntervalFromIndex(0)).clone();
                //calculate the start off tapping.
                if(playingTime != null){
                    playingTime %= staffSelected.getToneSequence().getPerformanceLength();
                    PerformanceNode pn = new PerformanceNode(playingTime);
                    pn.setPitch(null);
                    staff.getToneSequence().getPerformanceSequence().insert(0, pn);
                }
                //calculate the width of the last note (goes to end of measure)
                int widthTicks = SymbolConstants.DIVISOR/ts.getDenominator()*ts.getNominator();
                long widthTime = (60l*ModelConstants.PERFORMANCE_TO_SECOND*widthTicks)/(tn.getBPM()*(SymbolConstants.DIVISOR/ts.getDenominator()));
                PerformanceSequence performanceSeq = staff.getToneSequence().getPerformanceSequence();
                long difference = widthTime - performanceSeq.getDifference() % widthTime;
                PerformanceNode pn = ((PerformanceNode)staff.getToneSequence().getPerformanceSequence().getIntervalFromIndex(staff.getToneSequence().size()-1)).clone();
                tn.setDifference(staff.getLength());
                pn.setDifference(difference);
                staff.getToneSequence().getPerformanceSequence().add(pn);
                //set tempomap and timesignature
                ts.setDifference(staff.getLength());
                TempoMap tempoMap = new TempoMap();
                tempoMap.add(tn);
                Sequence<TimeSignature> sequence = new Sequence<TimeSignature>(TimeSignature.class);
                sequence.add(ts);
                staff.setTempoMap(tempoMap);
                staff.addSequence(sequence);
                int smallestValue = staff.getQuantizerNode().getQuantizer().getSmallestValue();                
                staff.getQuantizerNode().setQuantizer(new BPMQuantizer(smallestValue));
                staffSelected.getToneSequence().setLockPerformance(false);
            }
            if(staff.getLength() > 0){
                trackCollection.addTrack(new Track(staff));
            }
            start();
            this.requestFocus(); 
            //Set to beginstate
            this.setBackground(c1);
            label.setForeground(c2);
        }
    }

    public void keyReleased(KeyEvent e) {
        pressed = false;
    }
}
